package com.njbw.user.websocket;

import com.njbw.websocket.config.WebSocketServerConfig;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 要使用 websocket，在线连接数、客户端、连接会话都是比较重要的
 */
@Log4j2
@Component
@ServerEndpoint(value = "/njbw/socket", configurator = WebSocketServerConfig.class) // 这个注解表示这是一个 webSocket 节点
public class NjbwWebSocket {


    /**
     * 记录当前在线的连接数
     */
    private static final AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 存放所有的在线客户端
     */
    private static final Map<String, NjbwWebSocket> clients = new ConcurrentHashMap<>();

    /**
     * 某个客户端连接的 Session 会话
     */
    private Session session;

    /**
     * 标识当前会话的 key
     */
    private String erp = "";

    /**
     * 连接之后执行的方法
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) throws Exception {
        Map<String, Object> userProperties = config.getUserProperties();
        this.erp = (String) userProperties.get("erp");
        this.session = session;
        // 我们要查看该 erp 是否存在客户端列表中，如果存在我们要先 close 再替换
        if (clients.containsKey(this.erp)) {
            clients.get(this.erp).session.close();
            clients.remove(this.erp);
            onlineCount.decrementAndGet();
        }
        clients.put(this.erp, this);
        onlineCount.incrementAndGet();
        log.info("有新连接加入：{}，当前在线人数：{}", this.erp, onlineCount.get());
        sendMessage("连接成功", session);
    }

    /**
     * 断开执行的方法
     */
    @OnClose
    public void onClose() throws Exception {
        if (clients.containsKey(erp)) {
            clients.get(erp).session.close();
            clients.remove(erp);
            onlineCount.decrementAndGet();
        }
        log.info("有一处连接关闭 {}，当前在线人数：{}", this.erp, onlineCount.get());
    }

    /**
     * 客户端给我发消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws Exception {
        log.info("服务端收到客户端 {} 消息 {}", this.erp, message);
        // 心跳机制
        // 要和前端约定好，你定期给我发一些东西，我定期返给你
        if (message.equals("ping")) {
            // 这样我们就可以不断进行通信，而且不会断连
            this.sendMessage("pong", session);
        }
    }

    /**
     * 发生连接错误了
     */
    @OnError
    public void OnError(Session session, Throwable throwable) throws Exception {
        log.error("websocket: {} 发生错误，错误原因：{}", erp, throwable.getMessage(), throwable);
        session.close();
    }

    /**
     * 发送给前端消息————可能失败
     */
    public void sendMessage(String message, Session session) throws Exception {
        log.info("服务端给客户端 {} 发送消息：{}", this.erp, message);
        session.getBasicRemote().sendText(message);
    }

    /**
     * 客户端给所有客户端发消息
     */
    public void sendMessage(String message) throws Exception {
        for (Map.Entry<String, NjbwWebSocket> sessionEntry : clients.entrySet()) {
            String erp = sessionEntry.getKey();
            NjbwWebSocket webSocket = sessionEntry.getValue();
            webSocket.session.getBasicRemote().sendText(message);
        }
    }
}
